// Package utils implements common, reusable helpers
package utils

/*
Copyright 2021-2025 The k8gb Contributors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Generated by GoLic, for more details see: https://github.com/AbsaOSS/golic
*/

import (
	"encoding/json"
	"fmt"
	"os"

	yamlConv "github.com/ghodss/yaml"
	k8gbv1beta1 "github.com/k8gb-io/k8gb/api/v1beta1"
	istio "istio.io/client-go/pkg/apis/networking/v1"
	corev1 "k8s.io/api/core/v1"
	netv1 "k8s.io/api/networking/v1"
	gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1"
	// TODO: does this code run also for v1beta1 CRDs? No it does not
	// What if we add those to the schema? Look for "istio.io/client-go/pkg/apis/networking/v1" in the code
)

// FileToGSLB takes a file and returns a GSLB object
func FileToGSLB(file string) *k8gbv1beta1.Gslb {
	yaml, err := os.ReadFile(file)
	if err != nil {
		panic(fmt.Errorf("can't open example CR file: %s", file))
	}
	gslb, err := YamlToGslb(yaml)
	if err != nil {
		panic(err)
	}
	return gslb

}

// FileToIngress takes a file and returns an Ingress object
func FileToIngress(file string) *netv1.Ingress {
	ingressYaml, err := os.ReadFile(file)
	if err != nil {
		panic(fmt.Errorf("can't open example CR file: %s", file))
	}
	ingress, err := YamlToIngress(ingressYaml)
	if err != nil {
		panic(err)
	}
	return ingress
}

// FileToIstioVirtualService takes a file and returns a VirtualService object
func FileToIstioVirtualService(file string) *istio.VirtualService {
	yaml, err := os.ReadFile(file)
	if err != nil {
		panic(fmt.Errorf("can't open example CR file: %s", file))
	}
	vs, err := YamlToIstioVirtualService(yaml)
	if err != nil {
		panic(err)
	}
	return vs
}

// FileToIstioGateway takes a file and returns a Gateway object
func FileToIstioGateway(file string) *istio.Gateway {
	yaml, err := os.ReadFile(file)
	if err != nil {
		panic(fmt.Errorf("can't open example CR file: %s", file))
	}
	gw, err := YamlToIstioGateway(yaml)
	if err != nil {
		panic(err)
	}
	return gw
}

// FileToGatewayAPIHTTPRoute takes a file and returns a GatewayAPI HTTPRoute object
func FileToGatewayAPIHTTPRoute(file string) *gatewayapiv1.HTTPRoute {
	yaml, err := os.ReadFile(file)
	if err != nil {
		panic(fmt.Errorf("can't open example CR file: %s", file))
	}
	httproute, err := YamlToGatewayAPIHTTPRoute(yaml)
	if err != nil {
		panic(err)
	}
	return httproute
}

// FileToGatewayAPIGRPCRoute takes a file and returns a GatewayAPI GRPCRoute object
func FileToGatewayAPIGRPCRoute(file string) *gatewayapiv1.GRPCRoute {
	yaml, err := os.ReadFile(file)
	if err != nil {
		panic(fmt.Errorf("can't open example CR file: %s", file))
	}
	grpcroute, err := YamlToGatewayAPIGRPCRoute(yaml)
	if err != nil {
		panic(err)
	}
	return grpcroute
}

// FileToGatewayAPIGateway takes a file and returns a GatewayAPI Gateway object
func FileToGatewayAPIGateway(file string) *gatewayapiv1.Gateway {
	yaml, err := os.ReadFile(file)
	if err != nil {
		panic(fmt.Errorf("can't open example CR file: %s", file))
	}
	gateway, err := YamlToGatewayAPIGateway(yaml)
	if err != nil {
		panic(err)
	}
	return gateway
}

// FileToService takes a file and returns a Service object
func FileToService(file string) *corev1.Service {
	yaml, err := os.ReadFile(file)
	if err != nil {
		panic(fmt.Errorf("can't open example CR file: %s", file))
	}
	svc, err := YamlToService(yaml)
	if err != nil {
		panic(err)
	}
	return svc
}

// YamlToGslb takes yaml and returns a Gslb object
func YamlToGslb(yaml []byte) (*k8gbv1beta1.Gslb, error) {
	// yamlBytes contains a []byte of my yaml job spec
	// convert the yaml to json
	jsonBytes, err := yamlConv.YAMLToJSON(yaml)
	if err != nil {
		return &k8gbv1beta1.Gslb{}, err
	}
	// unmarshal the json into the kube struct
	gslb := &k8gbv1beta1.Gslb{}
	err = json.Unmarshal(jsonBytes, &gslb)
	if err != nil {
		return &k8gbv1beta1.Gslb{}, err
	}
	return gslb, nil
}

// YamlToIngress takes yaml and returns Gslb object
func YamlToIngress(yaml []byte) (*netv1.Ingress, error) {
	// yamlBytes contains a []byte of my yaml job spec
	// convert the yaml to json
	jsonBytes, err := yamlConv.YAMLToJSON(yaml)
	if err != nil {
		return &netv1.Ingress{}, err
	}
	// unmarshal the json into the kube struct
	ingress := &netv1.Ingress{}
	err = json.Unmarshal(jsonBytes, &ingress)
	if err != nil {
		return &netv1.Ingress{}, err
	}
	return ingress, nil
}

// YamlToService takes yaml and returns a Kubernetes Service object
func YamlToService(yaml []byte) (*corev1.Service, error) {
	// convert the yaml to json
	jsonBytes, err := yamlConv.YAMLToJSON(yaml)
	if err != nil {
		return &corev1.Service{}, err
	}
	// unmarshal the json into the kube struct
	svc := &corev1.Service{}
	err = json.Unmarshal(jsonBytes, &svc)
	if err != nil {
		return &corev1.Service{}, err
	}
	return svc, nil
}

// YamlToIstioVirtualService takes yaml and returns an Istio Virtual Service object
func YamlToIstioVirtualService(yaml []byte) (*istio.VirtualService, error) {
	// convert the yaml to json
	jsonBytes, err := yamlConv.YAMLToJSON(yaml)
	if err != nil {
		return &istio.VirtualService{}, err
	}
	// unmarshal the json into the kube struct
	vs := &istio.VirtualService{}
	err = json.Unmarshal(jsonBytes, &vs)
	if err != nil {
		return &istio.VirtualService{}, err
	}
	return vs, nil
}

// YamlToIstioGateway takes yaml and returns an Istio Gateway object
func YamlToIstioGateway(yaml []byte) (*istio.Gateway, error) {
	// convert the yaml to json
	jsonBytes, err := yamlConv.YAMLToJSON(yaml)
	if err != nil {
		return &istio.Gateway{}, err
	}
	// unmarshal the json into the kube struct
	gw := &istio.Gateway{}
	err = json.Unmarshal(jsonBytes, &gw)
	if err != nil {
		return &istio.Gateway{}, err
	}
	return gw, nil
}

// YamlToGatewayAPIHTTPRoute takes yaml and returns a GatewayAPI HTTPRoute object
func YamlToGatewayAPIHTTPRoute(yaml []byte) (*gatewayapiv1.HTTPRoute, error) {
	// convert the yaml to json
	jsonBytes, err := yamlConv.YAMLToJSON(yaml)
	if err != nil {
		return &gatewayapiv1.HTTPRoute{}, err
	}
	// unmarshal the json into the kube struct
	httproute := &gatewayapiv1.HTTPRoute{}
	err = json.Unmarshal(jsonBytes, &httproute)
	if err != nil {
		return &gatewayapiv1.HTTPRoute{}, err
	}
	return httproute, nil
}

// YamlToGatewayAPIGateway takes yaml and returns a GatewayAPI Gateway object
func YamlToGatewayAPIGateway(yaml []byte) (*gatewayapiv1.Gateway, error) {
	// convert the yaml to json
	jsonBytes, err := yamlConv.YAMLToJSON(yaml)
	if err != nil {
		return &gatewayapiv1.Gateway{}, err
	}
	// unmarshal the json into the kube struct
	gateway := &gatewayapiv1.Gateway{}
	err = json.Unmarshal(jsonBytes, &gateway)
	if err != nil {
		return &gatewayapiv1.Gateway{}, err
	}
	return gateway, nil
}

// YamlToGatewayAPIGRPCRoute takes yaml and returns a GatewayAPI GRPCRoute object
func YamlToGatewayAPIGRPCRoute(yaml []byte) (*gatewayapiv1.GRPCRoute, error) {
	// convert the yaml to json
	jsonBytes, err := yamlConv.YAMLToJSON(yaml)
	if err != nil {
		return &gatewayapiv1.GRPCRoute{}, err
	}
	// unmarshal the json into the kube struct
	grpcroute := &gatewayapiv1.GRPCRoute{}
	err = json.Unmarshal(jsonBytes, &grpcroute)
	if err != nil {
		return &gatewayapiv1.GRPCRoute{}, err
	}
	return grpcroute, nil
}
